fix(claude-code): dedupe compacted continuation sessions - #693
Conversation
Review follow-ups for the lineage election: - Union stamped lineage ids alongside raw ancestry markers. Deleting an intermediate transcript can disconnect a family's marker graph after stamping; a later rescan then reinserted the old sibling as a listable row in its own component, resurrecting the duplicate this feature removes, while the exact-id lookup kept treating both halves as one family through the shared lineage. Lineage ids are member uuids, so they share the marker namespace without cross-conversation collisions. - Preserve a stamped continuationLineageId across rescan upserts. The parser never emits the elected id, so the plain column replace eroded the stamp on every rescan and the reveal/dedupe comparison only held until the next scan touched the row. A metadata rewrite that loses continuation identity still drops the stamp with it. - Make DisjointSet::find iterative; a pathological union order could chain O(component) parents and recurse that deep on the sync thread. Pre-commit hook ran. Total eslint: 18, total circular: 0
|
Review + follow-up fixes landed in 3f568bd ( Findings fixed:
Both fixes have direct regression tests ( Cloud-plane interaction (audited, no change needed): newly-demoted siblings keep their pushed cloud rows — the vanished sweep's resolver runs Verification: orgtrack_core imported-history + claude tests green (the 8 pre-existing copilot/kimi failures are Windows-environment, present on the unmodified branch); tsc green; sidebar-loader + continuation-visibility vitest 23/23. Real-machine (Windows, v11 build), per the new coverage matrix:
|
Fresh-state runs sample only the post-change state space, so bugs living in the version TRANSITION stay invisible: PR #692's costliest defect (legacy flat cursors forced O(total) epoch rewrites) escaped every run that built its anchors with the new binary, and PR #693's lineage stamp was erased by the very next rescan the new build itself performed. The protocol now demands one cell where the OLD build writes the durable state and the NEW build must ride the ordinary incremental path over it, plus a second-order cycle proving state the new build stamps survives its own next scan. Fault-injection guidance also gains "inject the fault point the change ADDS", since the rotation list only encodes yesterday's failure modes. Pre-commit hook ran. Total eslint: 18, total circular: 0
Problem
Claude Code context compaction can rewrite the beginning of a continued transcript. The imported-history cache grouped continuation siblings only by the first user-message UUID, so a compacted conversation could split into multiple families even though the files shared a compact-boundary UUID. The sidebar then showed multiple same-title sessions. When an older sibling was already open, the reveal overlay could also render it beside the canonical roster winner.
The repository performance guard also lacked a provider × raw transition × UI state × topology gate. Earlier dual-machine evidence could therefore validate transport while leaving Claude Code compaction, raw identity derivation, and active-row rescan behavior untested.
Solution
continuationLineageIdwhile preserving legacy group-key metadata.org2-performance-guardto separate provider ingestion, local identity/listability, UI hydration, cloud transport, and remote rendering; require raw provider transitions, assumption-breaking identity fixtures, active/open/pinned rescan coverage, and explicit untested matrix cells.Potential risks
Architecture audit
Covered discovery/parser state, watermark invalidation, cache metadata and election ownership, exact-id lookup, optional IPC/schema compatibility, session-store projection, and sidebar reveal behavior. Execution dispatch, cloud sync, database schema, and source transcript formats were intentionally unchanged.
Performance audit
Verification
cargo test -p orgtrack_core --lib -- --test-threads=1— 537 passed, 8 ignored.cargo check -p org2— passed.cargo clippyfororgtrack_core— passed.pnpm exec tsc --noEmit --pretty false— passed.vitest runfor sidebar loader + continuation visibility — 23 passed.vitest run— 7852 passed, 1 pre-existing local-timezone failure inPrCommitsTab.test.ts; reproduced unchanged on the fix(key-vault): make CLI OAuth autodetect reliable #689/develop merge worktree. The failing test passes withTZ=UTC. The run also reported the existing Undici WebSocket/Event unhandled error fromuseCloudOrgSyncStatus.test.ts.0 / 0 / 1; searching the title rendered exactly one sidebar row.quick_validate.pyin an isolated PyYAML environment — passed (Skill is valid!).generate_openai_yaml.pyregenerated the skill interface metadata — passed.UI evidence
Validated both the ordinary roster and the harder active-old-sibling state in the isolated app. A static screenshot is not attached because the acceptance signal is the absence of a second identical row; the manual flow above was cross-checked against the exact three-row SQLite listability/lineage state and the accessibility tree reporting one matching button.